import socket, copy
from cryptography.fernet import Fernet
from xmlrpc import client
from struct import unpack_from
from math import floor
from time import sleep
from threading import Thread

class Utilities():
	handle = None
	recvWorkThread = None
	listeners = {}
	def __init__(self,sock=None):
		self.handle = 0x80000000
		self.listeners = {}
		if(sock==None):
			pass
		else:
			self.recvWorkThread = Thread(target=self.recvWorker,args=(sock,))
	def sendMessage(self,message,sock):
		length_bytes = len(message).to_bytes(4, byteorder='little')
		handler = self.getNextHandle()
		handler_bytes = handler.to_bytes(4, byteorder='little')
		sock.sendall(length_bytes + handler_bytes + message)
	def adminMessage(self,user,admins,message,socket):
		if(user in admins):
			self.sendMessage(message,socket)
			return True
		else:
			self.sendMessage(client.dumps(("You are not authorized to run this command!", user),methodname="ChatSendToLogin").encode(),socket)
			return False
		return False
	def getNextHandle(self):
		if(self.handle==0xffffffff):
			self.handle=0x80000000
		elif(self.handle==0x80000000):
			pass
		else:
			self.handle+=1
		return(self.handle)
	def msToHMS(self,ms):
		s = int(ms)/1000
		m = s/60
		s%=60
		h = m/60
		m%=60
		return str(floor(h))+"h"+str(floor(m))+"m"+str(round(s,2))+"s"
	def decryptFile(self,key,file):
		fernet = Fernet(key.read())
		decrypted = fernet.decrypt(file.read())
		file.seek(0)
		file.write(decrypted)
		file.truncate()
	def encryptFile(self,file,path):
		key = Fernet.generate_key()
		with open(path,"w+b") as k:
			k.write(key)
		fernet = Fernet(key)
		encrypted = fernet.encrypt(file.read())
		file.seek(0)
		file.write(encrypted)
		file.truncate()
	def recv(self,buffer):
		try:
			data = copy.copy(buffer[0])
			buffer.remove(data)
			return(data)
		except Exception as e:
			return(None)
	def forward(self,message,toWhom=0):
		self.listeners[toWhom].append(message)
	def listen(self,whoAmI=0):
		while(1):
			try:
				data,method = self.recv(self.listeners[whoAmI])
				return(data,method)
			except Exception as e:
				continue
	def recvWorker(self,sock):
		while(1):
			try:
				head = sock.recv(8)
				size,handle = unpack_from('<LL',head)
				body = sock.recv(size)
				data,method = client.loads(body,use_builtin_types=True)
				if(data==None):
					pass
				else:
					for i in self.listeners.keys():
						self.forward((data,method),i)
			except Exception as e:
				continue
	def registerListener(self,id):
		self.listeners[id] = []
	def splitData(self,data,meth):
		if meth == "TrackMania.PlayerChat":
			user = data[1]
			command = data[2].split(" ")[0]
			args = data[2][1:].split(" ")[1:]
			return(user,command,args)
		if meth == "TrackMania.PlayerFinish":
			userName = data[1]
			time = data[2]
			return(userName,time)
		if meth == "TrackMania.BeginChallenge":
			curChallName = data[0]['Name']
			return(curChallName)
		if meth == "TrackMania.PlayerConnect":
			user = data[0]
			return(user)